# 24.06.22——比特Python自学笔记
# 字典、文件

# 字典
# 字典是一种存储键值对的结构
# 键值对——计算机中的一个非常重要的概念
# 键(key)与值(value)之间有相对应的映射关系
# 根据key来快速找到value——哈希表
# 在Python的字典中可以同时包含很多个键值对
# 要求键不能重复

# 1.创建字典
a = {}
print(type(a))
b = dict()
print(type(b))

# 2.创建字典的同时设置初始值
a = {'id': 1, 'name': 'zhangsan'}
print(a)
# 一对键值对以冒号:来链接——key: value
# 不同键值对之间用逗号,来隔开——exp1, exp2
# 为了更清楚直观的了解键值对的数量，可以通过多行书写的方式来展示
a = {
    'id': 1,
    'name': 'zhangsan',  # 这里的逗号可有可无
}
print(a)
# 这种书写格式与C/C++中的自定义类型的书写格式相似
# 在一部字典中，键值对的数据类型是没有约束的


# 3.字典的查找——关键字'in'
print('id' in a)
print('class' in a)
# 关键字'in'只能判定键在字典中是否存在，无法判定值是否存在
print(1 in a)
# 通过 not in 来判定键在字典中是否不存在
print('class' not in a)
print('id' not in a)

# 4.字典的查找——[]根据key来获取value
print(a['id'])
print(a['name'])
# print(a['class'])   # KeyError——当前的键在字典中不存在

# 对于字典来说，使用in 或者 []都是非常高效的操作
# 对于列表来说，使用in是比较低效的，而使用[]是非常高效的
# 字典背后使用的数据结构为哈希表
# 列表背后使用的数据结构为顺序表

# 5.通过[]来新增元素

a = {
    'id': 1,
    'name': 'zhangsan',  # 这里的逗号可有可无
}

a['class'] = 101
print(a)

# 6.通过[]来修改value
a['class'] = '一年级1班'
print(a)
# 通过[]来新增/修改元素实际上就是通过[]在字典中查找对应的key
# 找到key则修改，未找到则新增

# 7.通过pop()方法来删除键值对
a.pop('id')  # pop()的参数为key，通过key来删除对应的键值对
print(a)

# 字典被设计出来的初衷，不是为了实现遍历，而是为了实现增删改查
# 哈希表在进行增删改查的效率是非常高的
# 哈希表是工作中最常用的数据结构，也是面试中的高频问题

# 8.通过循环来遍历字典
for key in a:
    print(key, a[key])
# 在C++/JAVA中，哈希表李的键值对存储的顺序是无序的
# 但是在Python中不一样，Python通过特殊的处理，能够保证遍历出来的顺序就是和插入顺序保持一致

# 9.通过keys获取到字典中的所有key
print(a.keys())
# 10.通过values获取到字典中的所有value
print(a.values())
# 11.通过items获取到字典中的所有键对值
print(a.items())
# 通过items()获取的键值对是通过元组获取每一对键值对，再通过列表存储这些键值对并进行返回
# 可以通过items搭配多元赋值操作可以单一取出键值对
for key, value in a.items():
    print(key, value)

# 合法key的类型
# 在Python中专门提供了一个hash()函数
# 通过hash()函数能够计算出一个变量的哈希值
print(hash(0))
print(hash(3.14))
print(hash('hash'))
print(hash(True))
print(hash((1, 2, 3)))

# 不能计算哈希值的类型
# print(hash([1, 2, 3]))  # TypeError: unhashable type: 'list'
# print(hash({1: 1, 2: 2, 3: 3}))     # TypeError: unhashable type: 'dict'

# 可变的对象一般是不可哈希的，不可变的对象，一般是可哈希的
'''
------------------------------------------------------------------------------------------
'''

# 文件
# 电影（.mp4）、歌曲（.mp3）、图片（.jpg）、文本（.txt）、表格（.xlsx）……
# 这些不同类型的数据都是保存在硬盘上的
# 文件——保存在硬盘中的数据
# 内存与硬盘的差异
# 1.内存的空间更小，硬盘空间更大
# 2.内存访问更快，硬盘访问更慢
# 3.内存成本更贵，硬盘成本更便宜
# 4.内存的数据易丢失，硬盘的数据持久化存储
# 此电脑=>C盘，D盘~ 这里面的内容都是硬盘上的内容，也都是文件
# 文件夹（目录）也是一种特殊的文件，目录文件
# 即使都是文件，文件里面存储数据的内容/格式差异很大

# 文件路径
# 由目录和文件构成的字符串，就称为‘文件的路径’
# 文件路径展示了文件在硬盘上的详细位置
# 文件路径是文件在硬盘上的身份标识，每一个文件的路径都是唯一的
# Windows中文件路径使用/或\都可以，在Linux中只能使用/
# 因此我们可以简单点认为：
# /——代表的是Linux系统
# \——代表的是Windows系统
# 在实际的使用中，由于\还代表的是转义标识符，如\n表示的是换行，因此在文件操作中文件路径我们统一用/来进行表示

# 文件操作
# 1.打开文件
# 通过open()可以打开一个文件
# 参数1：文件路径，打开指定路径下的文件；参数2：打开方式
# r——read，按读方式打开
# w——write，按照写方式打开
# a——append，也是写方式打开，把内容写到原有文件内容的末尾
# open()的返回值是一个文件对象，可以通过变量来接收
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'r')
print(f)
print(type(f))
# 文件的内容是在硬盘上的，此处的文件对象则是内存上的一个变量，后续读写文件操作，都是通过这个文件对象来进行
# 此处的文件对象就像一个‘遥控器’，计算机中把这种远程操作的‘遥控器’称为‘句柄’（handler)

# 2.关闭文件
# 通过close()可以关闭一个文件
f.close()
# 文件使用完后，一定要关闭
# 打开文件其实是在申请一定的系统资源~，不再使用文件的时候，资源就应该及时释放
# 否则就可能造成文件资源泄露
# 每个程序在启动的时候都会默认打开三个文件——标准输入、标准输出、标准错误
# 这些文件就对应这计算机的键盘、显示器
# 文件资源泄露是一个很重要的问题，不会第一时间暴露出来，而是会冷不丁偷袭一下

# Python有一个重要的机制——垃圾回收机制（GC)
# GC可以自动把不使用的变量进行释放
# 虽然Python有GC，让我们在一定程度上避免了资源泄露的问题，但是也不能完全依赖GC，因为GC的自动释放不一定及时

# 3.写文件
# 通过write()来可以对打开的文件进行写入
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'w')
f.write('hello world\n')
f.close()
# 想要对一个文件进行写入，那文件的打开方式就需要通过w进行打开
# 写方式打开有两种情况——直接写与追加写
# 如果是使用 w 方式来打开，会清空掉文件原有的内容
# 如果是使用 a 方式来打开，则不会清空文件原有内容
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'a')
f.write('hello world\n')
f.close()
# 如果文件对象已经被关闭，那么就意味着系统中与该文件相关的资源已经被释放，强行去写，就会出现异常

# 4.读文件
# 通过read()来读取已打开的文件
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'r')
res = f.read(2)  # read的参数为需要读取的字符数
print(res)
f.close()
# 读取的文件内容格式需要与代码中操作文件的编码格式相匹配
# 如GBK格式就需要匹配GBK格式的读取方式
# UTF8格式就需要匹配UTF8格式的读取方式
# open()函数中还可以传入关键字参数encoding='utf8'或者encoding='gbk'
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'r', encoding='utf-8')
res = f.read(2)
print(res)
f.close()

# 通过for循环来按行读取
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'r', encoding='utf-8')
for line in f:
    print(line, end='')
f.close()

# 通过 readlines 方法直接将整个文件的所有内容都读取出来，按照行组织到一个列表里
f = open('e:/Python/learning_py/24.06.22_learning/test.txt', 'r', encoding='utf-8')
read_list = f.readlines()
print(read_list)
f.close()
